{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Packages imported\n",
      "Extracting data/train-images-idx3-ubyte.gz\n",
      "Extracting data/train-labels-idx1-ubyte.gz\n",
      "Extracting data/t10k-images-idx3-ubyte.gz\n",
      "Extracting data/t10k-labels-idx1-ubyte.gz\n",
      "MNIST loaded\n"
     ]
    }
   ],
   "source": [
    "import tensorflow as tf\n",
    "import input_data\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "print (\"Packages imported\")\n",
    "\n",
    "mnist = input_data.read_data_sets(\"data/\", one_hot=True)\n",
    "trainimgs, trainlabels, testimgs, testlabels \\\n",
    " = mnist.train.images, mnist.train.labels, mnist.test.images, mnist.test.labels \n",
    "ntrain, ntest, dim, nclasses \\\n",
    " = trainimgs.shape[0], testimgs.shape[0], trainimgs.shape[1], trainlabels.shape[1]\n",
    "print (\"MNIST loaded\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "diminput  = 28\n",
    "dimhidden = 128\n",
    "dimoutput = nclasses\n",
    "nsteps    = 28\n",
    "weights = {\n",
    "    'hidden': tf.Variable(tf.random_normal([diminput, dimhidden])), \n",
    "    'out': tf.Variable(tf.random_normal([dimhidden, dimoutput]))\n",
    "}\n",
    "biases = {\n",
    "    'hidden': tf.Variable(tf.random_normal([dimhidden])),\n",
    "    'out': tf.Variable(tf.random_normal([dimoutput]))\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Network ready\n"
     ]
    }
   ],
   "source": [
    "def _RNN(_X, _W, _b, _nsteps, _name):\n",
    "    # 1. Permute input from [batchsize, nsteps, diminput] \n",
    "    #   => [nsteps, batchsize, diminput]\n",
    "    _X = tf.transpose(_X, [1, 0, 2])\n",
    "    # 2. Reshape input to [nsteps*batchsize, diminput] \n",
    "    _X = tf.reshape(_X, [-1, diminput])\n",
    "    # 3. Input layer => Hidden layer\n",
    "    _H = tf.matmul(_X, _W['hidden']) + _b['hidden']\n",
    "    # 4. Splite data to 'nsteps' chunks. An i-th chunck indicates i-th batch data \n",
    "    _Hsplit = tf.split(0, _nsteps, _H) \n",
    "    # 5. Get LSTM's final output (_LSTM_O) and state (_LSTM_S)\n",
    "    #    Both _LSTM_O and _LSTM_S consist of 'batchsize' elements\n",
    "    #    Only _LSTM_O will be used to predict the output. \n",
    "    with tf.variable_scope(_name) as scope:\n",
    "        \n",
    "        scope.reuse_variables()\n",
    "        lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(dimhidden, forget_bias=1.0)\n",
    "        _LSTM_O, _LSTM_S = tf.nn.rnn(lstm_cell, _Hsplit,dtype=tf.float32)\n",
    "    # 6. Output\n",
    "    _O = tf.matmul(_LSTM_O[-1], _W['out']) + _b['out']    \n",
    "    # Return! \n",
    "    return {\n",
    "        'X': _X, 'H': _H, 'Hsplit': _Hsplit,\n",
    "        'LSTM_O': _LSTM_O, 'LSTM_S': _LSTM_S, 'O': _O \n",
    "    }\n",
    "print (\"Network ready\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Network Ready!\n"
     ]
    }
   ],
   "source": [
    "learning_rate = 0.001\n",
    "x      = tf.placeholder(\"float\", [None, nsteps, diminput])\n",
    "y      = tf.placeholder(\"float\", [None, dimoutput])\n",
    "myrnn  = _RNN(x, weights, biases, nsteps, 'basic')\n",
    "pred   = myrnn['O']\n",
    "cost   = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(pred, y)) \n",
    "optm   = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost) # Adam Optimizer\n",
    "accr   = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(pred,1), tf.argmax(y,1)), tf.float32))\n",
    "init   = tf.global_variables_initializer()\n",
    "print (\"Network Ready!\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Start optimization\n",
      "Epoch: 000/005 cost: 1.666066025\n",
      " Training accuracy: 0.688\n",
      " Test accuracy: 0.560\n",
      "Epoch: 001/005 cost: 0.874283366\n",
      " Training accuracy: 0.750\n",
      " Test accuracy: 0.706\n",
      "Epoch: 002/005 cost: 0.749522536\n",
      " Training accuracy: 0.750\n",
      " Test accuracy: 0.766\n",
      "Epoch: 003/005 cost: 0.580684496\n",
      " Training accuracy: 0.938\n",
      " Test accuracy: 0.807\n",
      "Epoch: 004/005 cost: 0.577105198\n",
      " Training accuracy: 0.750\n",
      " Test accuracy: 0.806\n",
      "Optimization Finished.\n"
     ]
    }
   ],
   "source": [
    "training_epochs = 5\n",
    "batch_size      = 16\n",
    "display_step    = 1\n",
    "sess = tf.Session()\n",
    "sess.run(init)\n",
    "print (\"Start optimization\")\n",
    "for epoch in range(training_epochs):\n",
    "    avg_cost = 0.\n",
    "    #total_batch = int(mnist.train.num_examples/batch_size)\n",
    "    total_batch = 100\n",
    "    # Loop over all batches\n",
    "    for i in range(total_batch):\n",
    "        batch_xs, batch_ys = mnist.train.next_batch(batch_size)\n",
    "        batch_xs = batch_xs.reshape((batch_size, nsteps, diminput))\n",
    "        # Fit training using batch data\n",
    "        feeds = {x: batch_xs, y: batch_ys}\n",
    "        sess.run(optm, feed_dict=feeds)\n",
    "        # Compute average loss\n",
    "        avg_cost += sess.run(cost, feed_dict=feeds)/total_batch\n",
    "    # Display logs per epoch step\n",
    "    if epoch % display_step == 0: \n",
    "        print (\"Epoch: %03d/%03d cost: %.9f\" % (epoch, training_epochs, avg_cost))\n",
    "        feeds = {x: batch_xs, y: batch_ys}\n",
    "        train_acc = sess.run(accr, feed_dict=feeds)\n",
    "        print (\" Training accuracy: %.3f\" % (train_acc))\n",
    "        testimgs = testimgs.reshape((ntest, nsteps, diminput))\n",
    "        feeds = {x: testimgs, y: testlabels, istate: np.zeros((ntest, 2*dimhidden))}\n",
    "        test_acc = sess.run(accr, feed_dict=feeds)\n",
    "        print (\" Test accuracy: %.3f\" % (test_acc))\n",
    "print (\"Optimization Finished.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
